// Logger.cs
//
// Copyright (c) 2007 Mike Strobel
//
// This source code is subject to the terms of the Microsoft Reciprocal License (Ms-RL).
// For details, see <http://www.opensource.org/licenses/ms-rl.html>.
//
// All other rights reserved.

using System;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Text;

namespace Supremacy.Utility
{
    public static class Logger
    {
        private static bool initialized;
        private static object syncRoot;

        private static TextWriter debugWriter;
        private static TextWriter infoWriter;
        private static TextWriter warningWriter;
        private static TextWriter errorWriter;

        private static bool alwaysFlush;

        static Logger()
        {
            initialized = false;
            syncRoot = new object();
            infoWriter = Console.Out;
            warningWriter = Console.Error;
            errorWriter = Console.Error;
            alwaysFlush = false;

            Initialize();
        }

        public static TextWriter Debug
        {
            get
            {
                AssertInitialized();
                return debugWriter;
            }
        }

        public static TextWriter Info
        {
            get
            {
                AssertInitialized();
                return infoWriter;
            }
        }

        public static TextWriter Warning
        {
            get
            {
                AssertInitialized();
                return warningWriter;
            }
        }

        public static TextWriter Error
        {
            get 
            {
                AssertInitialized(); 
                return errorWriter;
            }
        }

        public static bool AlwaysFlush
        {
            get { return alwaysFlush; }
            set { alwaysFlush = value; }
        }

        private static void AssertInitialized()
        {
            if (!initialized)
            {
                throw new InvalidOperationException(
                    "Logger has not been initialized");
            }
        }

        public static void Initialize(string infoFilename,
            string warningFilename, string errorFilename)
        {
            Initialize(new StreamWriter(infoFilename),
                       new StreamWriter(warningFilename),
                       new StreamWriter(errorFilename));
                       
        }

        public static void Initialize(string logFilename)
        {
            FileStream outf = new FileStream(logFilename, 
                FileMode.Create, FileAccess.Write);
            StreamWriter writer = new StreamWriter(outf);
            Initialize(writer);
        }

        public static void Initialize(TextWriter log)
        {
            Initialize(log, log, log);
        }

        public static void Initialize(TextWriter info,
            TextWriter warning, TextWriter error)
        {
            if ((info == null) || (warning == null) || (error == null))
            {
                throw new ArgumentNullException();
            }
            infoWriter = info;
            warningWriter = warning;
            errorWriter = error;
            debugWriter = infoWriter;
            initialized = true;
        }

        public static void Initialize()
        {
            Initialize(Console.Out, Console.Error, Console.Error);
        }

        private static void Write(TextWriter writer, string text)
        {
            AssertInitialized();
            if (writer == null)
                return;
            StackTrace trace = new StackTrace(0);
            StringBuilder sb = new StringBuilder();
            MethodBase method = trace.GetFrame(2).GetMethod();
            sb.Append(method.ReflectedType.Name + ".");
            sb.Append(method.Name + "(): ");
            sb.Append(text);
            writer.WriteLine(sb.ToString());
#if !DEBUG
            if (AlwaysFlush)
#endif
                writer.Flush();
        }

        [Conditional("DEBUG")]
        public static void WriteDebug(string text)
        {
            Write(debugWriter, text);
        }

        [Conditional("DEBUG")]
        public static void WriteDebug(string format, params object[] arg)
        {
            Write(debugWriter, String.Format(format, arg));
        }

        public static void WriteInfo(string text)
        {
            Write(infoWriter, text);
        }

        public static void WriteInfo(string format, params object[] arg)
        {
            Write(infoWriter, String.Format(format, arg));
        }

        public static void WriteWarning(string text)
        {
            Write(warningWriter, text);
        }

        public static void WriteWarning(string format, params object[] arg)
        {
            Write(warningWriter, String.Format(format, arg));
        }

        public static void WriteError(string text)
        {
            Write(errorWriter, text);
        }

        public static void WriteError(string format, params object[] arg)
        {
            Write(errorWriter, String.Format(format, arg));
        }
    }
}
